#include "audioplugin.h"
#include <QtGui>
#include <Maestro/mcplugins.h>
#include <algorithm> // for random_shuffle
#include <ctime> // time used as random seed
using namespace std; // namespace for algorithms

AudioPlugin::AudioPlugin()
{
    //qDebug() <<Phonon::BackendCapabilities::availableAudioEffects();
    srand((time(NULL)));
    player=new AudioPlayer();
    connect(this,SIGNAL(fileChanged(MediaFile*)),player,SLOT(setMediaFile(MediaFile*)));
    mediaObject=new Phonon::MediaObject();
    connect(mediaObject,SIGNAL(stateChanged(Phonon::State,Phonon::State)),this,SLOT(stateChanged(Phonon::State,Phonon::State)));
    audioOutput =new Phonon::AudioOutput(Phonon::VideoCategory, this);
    Phonon::createPath(mediaObject,audioOutput);
    connect(mediaObject, SIGNAL(aboutToFinish()), this, SLOT(aboutToFinish())); // connect signal from media object
    ffTimer = new QTimer(this);
    connect(ffTimer,SIGNAL(timeout()),this,SLOT(ff()));
    rwTimer = new QTimer(this);
    connect(rwTimer,SIGNAL(timeout()),this,SLOT(rw()));
    connect(mediaObject,SIGNAL(stateChanged(Phonon::State,Phonon::State)),this,SLOT(stateChange(Phonon::State,Phonon::State)));
    connect(mediaObject,SIGNAL(currentSourceChanged(Phonon::MediaSource)),this,SLOT(mediaSourceChanged(Phonon::MediaSource)));
    player->setMinimumWidth(QApplication::desktop()->screen(0)->width());
    player->setMinimumHeight(QApplication::desktop()->screen(0)->height());
    index=0;
}

QString AudioPlugin::getName() {
    return "Music";
}

void AudioPlugin::test() {

}

QIcon AudioPlugin::getImage() {
    return QIcon(":/imgs/3F00_musicButton.png");
}

QIcon AudioPlugin::getIcon(MediaFile * mediaFile) {
    return QIcon(":/imgs/Music.png");
}

QStringList AudioPlugin::getExtensions() {
    QStringList list=QStringList();
    list.append("avi");
    return list;
}

QWidget * AudioPlugin::getInterface() {
    return player;
}

void AudioPlugin::setMediaFile(MediaFile * mediaFile) {
    mediaObject->setCurrentSource(mediaFile->fileLocation+"/"+mediaFile->shortName);
    mediaObject->play();
}

void AudioPlugin::setMediaQueue(QList<MediaFile *> * files, int start) {
    if(index==start&&sourceQueue==files) {
        return;
    }
    sourceQueue=files;
    ffTimer->stop();
    rwTimer->stop();
    acceleratedPlay=false;
    mediaObject->queue().clear();
    queue.clear();
    tmpQueue.clear();
    index=0;
    foreach(MediaFile * file, *files) { // append each file to queue
        Phonon::MediaSource source(file->fileLocation+"/"+file->shortName);
        queue.append(source);
        tmpQueue.append(source); // keep a copy for restoration purposes
        qDebug() << file->fileLocation<<"/"<<file->shortName;
    }
    if(queue.size()>start) {
        qDebug() <<"setting element at "<<QString::number(start)<<" "<<queue.at(start).fileName();
        mediaObject->setCurrentSource(queue.at(start).fileName()); // set the sources to play when the current source has finished
        index=start;
        mediaObject->play();

        emit stateChanged(true);
        emit fileChanged(mediaObject->currentSource().fileName(), index, queue.size());
        determineSong();
        qDebug()<< "Media Queue has been set.";
        setShuffleState(shuffle); // because media queue has been reset, need to recheck the shuffle state
                                  // no need to recheck the repeat state as that's done when songs finish
    } else {
        qDebug() <<"starting value too large";
    }
}

void AudioPlugin::play() {
    ffTimer->stop();
    rwTimer->stop();
    if(mediaObject->state()==Phonon::PausedState||mediaObject->state()==Phonon::StoppedState||acceleratedPlay)
    { // if paused, stopped, rewinding, or forwarding...
        mediaObject->play();
        acceleratedPlay = false;
        emit stateChanged(true);
        emit fileChanged(mediaObject->currentSource().fileName(), index, queue.size());
        determineSong();
    } else {
        mediaObject->pause();
        emit stateChanged(false);
        emit fileChanged(mediaObject->currentSource().fileName(), index, queue.size());
        determineSong();
    }
}

void AudioPlugin::fastForward() {
    acceleratedPlay = true;
    emit stateChanged(false);
    rwTimer->stop();
    ffTimer->start(100);
}

void AudioPlugin::ff() {
    if (mediaObject->remainingTime()>0){
         mediaObject->seek(mediaObject->currentTime()+1000); // 1 second
     } else { // reached end of file
         mediaObject->stop();
         acceleratedPlay = false;
     }
}

void AudioPlugin::rewind() {
    acceleratedPlay = true;
    emit stateChanged(false);
    ffTimer->stop();
    rwTimer->start(100);
}

void AudioPlugin::rw() {
    if (mediaObject->currentTime()>0){
        if(mediaObject->currentTime()-1000<=0) { // the next seek is at or past the beginning
            rwTimer->stop();
            acceleratedPlay = false;
        }
        mediaObject->seek(mediaObject->currentTime()-1000); // 1 second

     } else { // reached end of file
         rwTimer->stop();
         acceleratedPlay = false;
         //if(acceleratedMute) {
         //    audioOutput->setMuted(false);
         //    acceleratedMute=false;
         //}
     }
}

void AudioPlugin::stop() {
    ffTimer->stop();
    rwTimer->stop();
    emit stateChanged(false);
    mediaObject->stop();
}

void AudioPlugin::setVolume(int volume) {
    audioOutput->setVolume(volume/100.0);
}

void AudioPlugin::aboutToFinish()
{
    //index = queue.indexOf(mediaObject->currentSource()); // this line is redundant

    switch(repeat) {
    case 1: // Repeat All
        index++;
        if (queue.size() > index) { // if not at the end of the queue, enqueue the next song
            mediaObject->enqueue(queue.at(index));
            qDebug() <<"Now playing: "<<queue.at(index).fileName();
        }
        else { // end of queue, thus reset the index and then enqueue the next song
            index = 0;
            mediaObject->enqueue(queue.at(index));
            qDebug() <<"Now playing: "<<queue.at(index).fileName();
        }
        break;
    case 2: // Repeat One
        mediaObject->seek(0); // seek to the beginning of the track
        qDebug() <<"Now playing: "<<queue.at(index).fileName();
        break;
    case 0: // Repeat Off
    default: // enqueue next song to be played, but queue doesn't repeat when end reached
        index++;
        if (queue.size() > index) {
            mediaObject->enqueue(queue.at(index));
            qDebug() <<"Now playing: "<<queue.at(index).fileName();
        }
        else {
            emit stateChanged(false); // media has stopped, thus change state
            index = 0; // reset to start of list, but do not enqueue
            mediaObject->setCurrentSource(queue.at(index).fileName());
            qDebug() <<"End of queue reached.";
        }
        break;
    }
}

void AudioPlugin::setShuffleState(bool shuffleState) {
    this->shuffle=shuffleState;
    qDebug()<<"shuffle = " << shuffle;
    if(queue.isEmpty()) return; // shuffle has been clicked before the queue has been set. set the queue first
    if(shuffle) // shuffle the queue
    {
        while(queue.operator ==(tmpQueue)) // ensure that you don't shuffle to the original queue
            random_shuffle(queue.begin(), queue.end());
        qDebug()<<"Queue is shuffled";
        for(int i = 0; i < queue.size(); i++)
                qDebug()<<queue.at(i).fileName();
    }
    else // sort the queue with help from the temp queue
    {
        for(int i = 0; i < queue.size(); ++i)
            queue.replace(i, tmpQueue[i]);
        qDebug()<<"Queue is sorted";
    }
}

void AudioPlugin::setRepeatState(int repeatState) {
    this->repeat=repeatState;
    qDebug() << "repeat = " << repeat << " (0 = off, 1 = all, 2 = one)";
}

bool AudioPlugin::isPlaying() {
    if(!ffTimer->isActive()&&!rwTimer->isActive()&&mediaObject->state()==Phonon::PlayingState) {
        return true;
    }

    return false;
}

void AudioPlugin::next() {
    qDebug("loading next");
    if(index+1<queue.size()) { // if not at the end, go to next song
        index++;
        qDebug()<<queue.at(index).fileName();
        mediaObject->setCurrentSource(queue.at(index).fileName());
        mediaObject->play();
        emit stateChanged(true);
        emit fileChanged(mediaObject->currentSource().fileName(), index, queue.size());
        determineSong();
    }
    else { // if at the end, go back to the first song
        index = 0;
        qDebug()<<queue.at(index).fileName();
        mediaObject->setCurrentSource(queue.at(index).fileName());
        mediaObject->play();
        emit stateChanged(true);
        emit fileChanged(mediaObject->currentSource().fileName(), index, queue.size());
        determineSong();
    }
}

void AudioPlugin::previous() {
    qDebug("loading previous");
    if(index>0) { // if not at the beginning, go to the previous song
        index--;
        qDebug()<<queue.at(index).fileName();
        mediaObject->setCurrentSource(queue.at(index).fileName());
        mediaObject->play();
        emit stateChanged(true);
        emit fileChanged(mediaObject->currentSource().fileName(), index, queue.size());
        determineSong();
    }
    else { // if at the beginning, go to the last song in the queue
        index = queue.size()-1;
        qDebug()<<queue.at(index).fileName();
        mediaObject->setCurrentSource(queue.at(index).fileName());
        mediaObject->play();
        emit stateChanged(true);
        emit fileChanged(mediaObject->currentSource().fileName(), index, queue.size());
        determineSong();
    }
}

void AudioPlugin::stateChanged(Phonon::State newS, Phonon::State oldS) {
    if(newS==Phonon::ErrorState) {
        qDebug()<<mediaObject->errorString();
    }
}

bool AudioPlugin::setSlider(Phonon::SeekSlider *slider) {
    slider->setMediaObject(mediaObject);

    return true;
}

void AudioPlugin::stateChange(Phonon::State newS, Phonon::State oldS) {
    if(newS==Phonon::ErrorState) {
        emit error("Error. The file could not be played");
    }
}

void AudioPlugin::mediaSourceChanged(Phonon::MediaSource source) {
    emit fileChanged(source.fileName(),queue.indexOf(source),queue.size());
    qDebug()<<"index is"<<index;
    if(sourceQueue->size()>index&&index>-1) {

        determineSong();
    }
}

void AudioPlugin::determineSong() {
    for(int i=0; i<sourceQueue->size(); i++) {
        MediaFile * file=sourceQueue->at(i);
        if(file->fileLocation+"/"+file->shortName==queue.at(index).fileName()) {
            emit fileChanged(sourceQueue->at(i));
        }
    }
}

Q_EXPORT_PLUGIN2(bmc_audioplugin, AudioPlugin)
